--[[
 -- *名称:FourTakePairTypeAnalyzer
 -- *描述:四带二牌型分析器
 -- *版权:Copyright © 2016-2018 深圳市三只小熊科技有限公司 版权所有
 -- *作者:Administrator
 -- *创建日期:2017-11-09
 -- *修改日期:2017-11-09
 ]]
local DdzSuitAnalyzer = require(basePath.."suit/ddzsuitanalyzer");
local BombTypeAnalyzer =  require(basePath.."suit/bomb/bombtypeanalyzer");
local Cards = require(basePath .. "domain/cards");
local FourTakePairTypeAnalyzer = pokercore.class(DdzSuitAnalyzer,false);
local TUPLE_SIZE = 8;
local PairAnalyzer  = require(basePath .. "suit/pair/pairtypeanalyzer") ;

local pairTypeAnalyzer = pokercore.new(PairAnalyzer);

function FourTakePairTypeAnalyzer:getSuitType()
	return DdzCardTypes.FOUR_TAKE_PAIR;
end

function FourTakePairTypeAnalyzer:doCheckRule( cards, term, result )
	if result:getCardNum() == TUPLE_SIZE then -- 八张牌，考虑 44443355 55556666
		if result:getNoneLaziValueCounter():hasJoker() then -- 四带两对不能出现王
			return false;
		end

		if result:isAllCardLazi() then  -- 全是癞子
			return false;
		end

		local allValues = result:getNoneLaziValueCounter():getAllValues(); -- 非癞子的点数
		local allValueSize = #allValues;
		if allValueSize >3 then -- 四带两对牌型最多只有3种点数
			return false;
		else  -- 只有1种,2种或3种点数的情况
			local laiziCardNum = result:getLaziCardNum();
			if laiziCardNum >= 4 then -- 一定可以组成四带两对
				return true;
			else -- 癞子数小于三个
				if allValueSize == 2 then -- 两种点数
					return true;
				else -- 三种点数  排除点数分布 133 和 134 牌型
					local count = 0;
					for _,value in ipairs(allValues) do
						local valueNum = result:getNoneLaziValueCounter():getValueCount(value);
						if valueNum >=3 then 
							count = count + 1;
						end
					end

					if count >= 2 then 
						return false;
					else 
						return true;
					end

				end
			end
		end
	else 
		return false;
	end
end

function FourTakePairTypeAnalyzer:doAnalysizeLaizi( cards, term, onlyMaxValue )
	local cardsResult = {};
	local result = cards:getResult();
	local allValues = result:getNoneLaziValueCounter():getAllValues();
	local allValueSize = #allValues ;
	local laiziCardNum = result:getLaziCardNum();
	-- 只有2种或3种点数的情况
	if laiziCardNum >= 4 then -- 一定可以组成四带两对
		if laiziCardNum == 7 or laiziCardNum == 6 then -- 3******* 34******
			self:makeItInAllValues(cards, term, onlyMaxValue, cardsResult);
		elseif laiziCardNum == 5 then 
			if allValueSize == 1 or allValueSize == 2 then -- 388******
				self:makeItInAllValues(cards, term, onlyMaxValue, cardsResult);
			else -- 345******
				self:makeItInSomeValues(cards, term, onlyMaxValue, cardsResult);
			end
		else -- 四个癞子 
			if allValueSize == 1 then 
				self:makeItInAllValues(cards, term, onlyMaxValue, cardsResult);
			elseif allValueSize == 2 then -- 两种点数 2333**** 2233****
				local count_3_values = result:getNoneLaziValueCounter():getValuesInCount(3);
				if #count_3_values > 0 then -- 2333****
					self:makeItInSomeValues(cards, term, onlyMaxValue, cardsResult);
				else -- 2233**** 可以组成任意牌型
					self:makeItInAllValues(cards, term, onlyMaxValue, cardsResult);
				end
			else -- 三种点数 2344****
				self:makeItInSomeValues(cards, term, onlyMaxValue, cardsResult);
			end
		end
	else -- 癞子数小于三个 
		self:makeItInSomeValues(cards, term, onlyMaxValue, cardsResult);
	end
	return cardsResult;
end
---
 -- 在已知值中寻找四带两对
 -- @DateTime 2017-11-09
 -- @param    cards [description]
 -- @param    term [description]
 -- @param    onlyMaxValue [description]
 -- @param    cardsResult [description]
 -- @return    [description]
 --
function FourTakePairTypeAnalyzer:makeItInSomeValues( cards, term, onlyMaxValue, cardsResult )
	local result = cards:getResult();
	local laiziCardList = cards:subList(result:getCardNum() - result:getLaziCardNum()+1, result:getCardNum());
	local allValues = result:getNoneLaziValueCounter():getAllValues();
	local laiziCardNum = result:getLaziCardNum();
	for i = #allValues, 1, -1 do 
		local i_valueTemp = allValues[i];
		result:setSortFirstValue(i_valueTemp);
		local i_valueTempNum = result:getNoneLaziValueCounter():getValueCount(i_valueTemp);
		local i_needLaiziNum = 4 - i_valueTempNum;
		if i_needLaiziNum <= laiziCardNum then 
			local laiziCardIndex = 0;
			for i_laiziIndex = 1, i_needLaiziNum do
				laiziCardIndex = laiziCardIndex + 1; 
				laiziCardList[laiziCardIndex]:changeCard(i_valueTemp);
			end
			for j = #allValues, 1, -1 do 
				local j_valueTemp = allValues[j];
				if j_valueTemp ~= i_valueTemp then --// 其余赋值needLaizinum_j个癞子
					local j_valueTempNum = result:getNoneLaziValueCounter():getValueCount(j_valueTemp);
					if j_valueTempNum % 2 ~= 0 then  -- // 遇单补齐
						i_needLaiziNum = i_needLaiziNum + 1;
						if i_needLaiziNum <= laiziCardNum then 
							laiziCardIndex = laiziCardIndex + 1;
							laiziCardList[laiziCardIndex]:changeCard(j_valueTemp);
						else 
							break;
						end
					end
				end
			end
			--如果有剩下补齐成对儿
			for j = laiziCardIndex+1, laiziCardNum do 
				laiziCardList[j]:changeCard(laiziCardList[laiziCardIndex+1]:getNumber());
			end

			if i_needLaiziNum <= laiziCardNum then 
				local cardsCopy = cards:clone();	
				self:analysize(cardsCopy,term);
				table.insert(cardsResult,cardsCopy:clone());
				if onlyMaxValue then 
					break;
				end
			end
		end
	end
end
---
 -- 遍历所有值寻找四带两对
 -- @DateTime 2017-11-09
 -- @param    cards [description]
 -- @param    term [description]
 -- @param    onlyMaxValue [description]
 -- @param    cardsResult [description]
 -- @return    [description]
 --
function FourTakePairTypeAnalyzer:makeItInAllValues( cards, term, onlyMaxValue, cardsResult )
	local result = cards:getResult();
	--print("FourTakePairTypeAnalyzer:makeItInAllValues cards",cards);
	local laiziCardList = cards:subList(result:getCardNum() - result:getLaziCardNum()+1, result:getCardNum());
	local allValues = result:getNoneLaziValueCounter():getAllValues(); -- 非癞子的点数
	local laiziCardNum = result:getLaziCardNum();
	for valueTemp = PokerGameConstant.NUMBER_2_VALUE, PokerGameConstant.NUMBER_3_VALUE, -1 do 
		result:setSortFirstValue(valueTemp);
		local valueTempNum = result:getNoneLaziValueCounter():getValueCount(valueTemp);
		local laiziCardIndex = 0;
		local needLaiziNum = 4 - valueTempNum;
		--print("####### needLaiziNum->",needLaiziNum);
		--print("####### laiziCardList->",#laiziCardList);
		for i = 1, needLaiziNum do 
			laiziCardIndex = laiziCardIndex + 1;
			laiziCardList[laiziCardIndex]:changeCard(valueTemp);
		end

		for j = #allValues, 1,-1 do 
			local j_valueTemp = allValues[j];
			if j_valueTemp ~= valueTemp then 
				local j_valueTempNum = result:getNoneLaziValueCounter():getValueCount(j_valueTemp);
				if j_valueTempNum % 2 ~= 0 then -- 遇单补齐
					laiziCardIndex = laiziCardIndex + 1;
					laiziCardList[laiziCardIndex]:changeCard(j_valueTemp);
				end
			end
		end
		-- 如果有剩下补齐成对儿
		for j = laiziCardIndex+1, laiziCardNum do 
			laiziCardList[j]:changeCard(laiziCardList[laiziCardIndex+1]:getNumber());
		end
		local cardsCopy = cards:clone();	
		self:analysize(cardsCopy,term);
		table.insert(cardsResult,cardsCopy:clone());
		if onlyMaxValue then 
			break; -- 取完最大一组就跳出
		end
	end
end


--提牌算法


--@Override
function FourTakePairTypeAnalyzer:containsPossibleCards( handCards,  term) 
	local result = handCards:getResult();
	return (result:getCardNum() - result:getJokerCardNum()) >= TUPLE_SIZE;
end

--/** 最多使用癞子的数量 */
local  MAX_USE_LAIZI_CARD_NUM = 6;

--/** 防重复判定的比例值 参照 int key = count_3_value * TUPLE_WEIGHT + count_1_value_a + count_1_value_b; */
local TUPLE_WEIGHT = 1000000;

--/** 癞子权重，区分癞子变成的5 和 原本就是5 */
local LAIZI_WEIGHT = 1000;
	
--@Override
function FourTakePairTypeAnalyzer:doListPossibleCards(handCards, term) 
	local cardsResult = {} ;
	--// 非癞子部分
	local result = handCards:getResult();
	local noneLaiziCardList = handCards:subList(1, result:getNoneCardNum());
	local noneLaiziCards = DdzTypeUtil.createCardsCopy(noneLaiziCardList);
	noneLaiziCards:setResult(handCards:getResult():clone());
	local noneLaiziCardsResult = noneLaiziCards:getResult();
	noneLaiziCardsResult:collectNumber(noneLaiziCards, term);
	--// 癞子部分
	local laiziCardList = handCards:subList(result:getNoneCardNum()+1, result:getCardNum());
	local laiziCards = DdzTypeUtil.createCardsCopy(laiziCardList);
	laiziCards:setResult(handCards:getResult():clone());
	local laiziCardsResult = laiziCards:getResult();
	laiziCardsResult:collectNumber(laiziCards, term);
	
	local maxLoseValue = 0; --// 寻找最大遗失的牌 让***5可以出现，但是仅一次
	for valueTemp = PokerGameConstant.NUMBER_2_VALUE --// 从小开始
			,PokerGameConstant.NUMBER_3_VALUE, -1 do
		if (result:getNoneLaziValueCounter():getValueCount(valueTemp) == 0) then
			maxLoseValue = valueTemp;
			break;
		end
	end
	local laiziCardNum = result:getLaziCardNum();
	local maxUseLaiziCardNum = MAX_USE_LAIZI_CARD_NUM < laiziCardNum and MAX_USE_LAIZI_CARD_NUM or laiziCardNum;
	local exsitKeys = {}; -- // 记录已经组成三带一的value
	--print("FourTakePairTypeAnalyzer:doListPossibleCards maxUseLaiziCardNum->",maxUseLaiziCardNum);
	for useLaiziCardNum = 0,maxUseLaiziCardNum do
		if (useLaiziCardNum < MAX_USE_LAIZI_CARD_NUM) then --// 用了 0.1.2.3 个癞子
			for valueTemp = PokerGameConstant.NUMBER_3_VALUE  --// 从小开始
					,PokerGameConstant.NUMBER_2_VALUE do
				local modelCardsCopy = noneLaiziCards:clone(); -- // 常规牌副本
				local modelResultCopy = modelCardsCopy:getResult();
				local useLaiziCardList = DdzTypeUtil.cloneSublistedCards(laiziCards, 1, useLaiziCardNum); --// 补癞子
				local valueTempNum = modelResultCopy:getNoneLaziValueCounter():getValueCount(valueTemp);
				local needLaiziCardNum = BombTypeAnalyzer.TUPLE_SIZE - valueTempNum;
				needLaiziCardNum = needLaiziCardNum > 0 and needLaiziCardNum or 0;
				if (needLaiziCardNum == 0) then
					local removedCardList = DdzTypeUtil.cloneRemovedCards(modelCardsCopy, valueTemp, BombTypeAnalyzer.TUPLE_SIZE);
					local tupleCards = pokercore.new(Cards,removedCardList);
					local remainCards = DdzTypeUtil.cloneCardsAndAddCardList(modelCardsCopy, useLaiziCardList);
					local takenCardsList = self:repeatSelectPairCards(remainCards, 2, term);
					for _,takenCards in ipairs(takenCardsList) do
						----dump(tupleCards,"合并之前")
						local resultCards = DdzTypeUtil.cloneCardsAndAddCards(tupleCards, takenCards);
						----dump(resultCards,"合并之后")
						local key = valueTemp * TUPLE_WEIGHT;
						for _,card in ipairs(takenCards.cardList) do
							key = key + card:getValue();
							if card:isLazi() then -- // 癞子权重，区分癞子变成的5 和 原本就是5
								key = key + card:getValue() * LAIZI_WEIGHT;
							end
						end
						if not exsitKeys[key] and self:match(resultCards, term) then
							exsitKeys[key] = true;
							--// 保证排序
							resultCards:getResult():setSortFirstValue(valueTemp);
							self:analysize(resultCards, term);
							table.insert(cardsResult,resultCards);
						end
					end
				else -- // 需要癞子来拼凑
					if (needLaiziCardNum == BombTypeAnalyzer.TUPLE_SIZE 
							and valueTemp ~= maxLoseValue) then
						--// 这里是对癞子做tuple的去重
						--// 否则会出现 ****带89 既能是 3333带89 也能是 4444带89 5555带89
						--continue;
					
					elseif (useLaiziCardNum >= needLaiziCardNum) then -- // 癞子足够拼凑
						local removedCardList = DdzTypeUtil.cloneRemovedCards(modelCardsCopy, valueTemp, valueTempNum);
						for i = 1, needLaiziCardNum  do
							local laiziCard =  table.remove(useLaiziCardList,1);
							laiziCard:changeCard(valueTemp);
							table.insert(removedCardList,laiziCard);
						end
						for _,laiziCard in ipairs(useLaiziCardList) do
							laiziCard:changeCard(laiziCard:getValue());
						end
						local tupleCards = pokercore.new(Cards,removedCardList);
						local remainCards = DdzTypeUtil.cloneCardsAndAddCardList(modelCardsCopy, useLaiziCardList);
						local takenCardsList = self:repeatSelectPairCards(remainCards, 2, term);
						for _, takenCards in ipairs(takenCardsList) do
							local resultCards = DdzTypeUtil.cloneCardsAndAddCards(tupleCards, takenCards);
							local key = valueTemp * TUPLE_WEIGHT;
							for _,card in ipairs(takenCards.cardList) do
								key = key + card:getValue();
								if card:isLazi() then -- // 癞子权重，区分癞子变成的5 和 原本就是5
									key = key + card:getValue() * LAIZI_WEIGHT;
								end
							end
							if not exsitKeys[key] and self:match(resultCards, term) then
								exsitKeys[key] = true;
								--// 保证排序
								resultCards:getResult():setSortFirstValue(valueTemp);
								self:analysize(resultCards, term);
								table.insert(cardsResult,resultCards);
							end
						end
					end
				end
			end
		else  -- // 用了 4个癞子
			for valueTemp = PokerGameConstant.NUMBER_3_VALUE --// 从小开始
					, PokerGameConstant.NUMBER_2_VALUE do
				local modelCardsCopy = laiziCards:clone();  --// 常规牌补上癞子
				local modelResultCopy =  modelCardsCopy:getResult();
				if (modelResultCopy:getAllValueCounter():getValueCount(valueTemp) >= BombTypeAnalyzer.TUPLE_SIZE) then
					local removedCardList = DdzTypeUtil.cloneRemovedCards(modelCardsCopy, valueTemp, BombTypeAnalyzer.TUPLE_SIZE);
					local tupleCards = new(Cards,removedCardList);
					local takenCardsList = self:repeatSelectPairCards(modelCardsCopy, 2, term);
					for _,takenCards in ipairs(takenCardsList) do
						local resultCards = DdzTypeUtil.cloneCardsAndAddCards(tupleCards, takenCards);
						for _,card in ipairs(resultCards.cardList) do
							if card:hasNotChanged() then -- // 有的经过处理已经被赋值了不能再改变
								card:changeCard(card:getValue());
							end
						end
						if (self:match(resultCards, term)) then
							--// 保证排序
							resultCards:getResult():setSortFirstValue(valueTemp);
							self:analysize(resultCards, term);
							table.insert(cardsResult,resultCards);
						end
					end
				end
			end
		end
	end
	return cardsResult;
end

--[[
/**
 * 在固定牌组中寻找repeat张单牌 <br>
 * 比如在 5。5。6。7 中寻找两张单牌 5.5 5.6 5.7 6.7   注意这里已经去重了 6.7 和 7.6 不会同时出现 
 * 
 * @param cards
 * @param repeat
 * @param term
 * @param onlyMaxValue
 * @return
 */
 ]]
function  FourTakePairTypeAnalyzer:repeatSelectPairCards( cards,  repeatSize,  term) 
	local modelCards = DdzTypeUtil.cloneCardsAndAddCardList(cards, nil); --// 常规牌补上癞子
	local modelResult = modelCards:getResult();
	modelResult:collectNumber(modelCards, term);
	if (modelResult:getCardNum() < 2 * repeatSize) then --// 数量不足
		return {};
	end
	local resultCardsList = pairTypeAnalyzer:listPossibleCards(modelCards, term); --// 记录最终结果
	----dump(resultCardsList,"resultCardsList");
	----print("repeatSize->",repeatSize);
	if (#resultCardsList ~= 0) then
		for i = 1,repeatSize-1 do -- // 上面已经获取了一次了
			local exsitKeys = {} -- // 每一步都去重
			local currentCardsList = pokercore.clone(resultCardsList);
			resultCardsList = {}; --// 清空上一步的结果
			----dump(modelCards,"modelCards->");
			for _,preCards in ipairs(currentCardsList) do
				----dump(preCards,"preCards");
				local remainCards = DdzTypeUtil.cloneCardsAndRemoveCards(modelCards, preCards);
				----dump(remainCards,"remainCards");
				local nextCardsList = pairTypeAnalyzer:listPossibleCards(remainCards, term);
				----dump(nextCardsList,"nextCardsList");
				for _,nextCards in ipairs(nextCardsList) do
					local combinedCards = DdzTypeUtil.cloneCardsAndAddCards(preCards, nextCards);
					----dump(combinedCards,"combinedCards");
					local key = 0;
					for _,card in ipairs(combinedCards:getCardList()) do
						key = key + card:getValue();
						if card:isLazi() then -- // 癞子权重，区分癞子变成的5 和 原本就是5
							key = key + LAIZI_WEIGHT;
						end
					end
					--print("key-->",key);
					--dump(exsitKeys,"exsitKeys->")
					if (not exsitKeys[key]) then
						exsitKeys[key] = true;
						--dump(combinedCards,"combinedCards");
						table.insert(resultCardsList,combinedCards);
						--dump(resultCardsList,"resultCardsList341234");
					end
				end
			end
		end
	end
	----print("###################################")
	----dump(resultCardsList,"resultCardsList2");
	return resultCardsList;
end


return FourTakePairTypeAnalyzer;

